home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / cpu / h6280 / h6280.c < prev    next >
C/C++ Source or Header  |  2000-05-04  |  14KB  |  506 lines

  1. /*****************************************************************************
  2.  
  3.     h6280.c - Portable HuC6280 emulator
  4.  
  5.     Copyright (c) 1999, 2000 Bryan McPhail, mish@tendril.co.uk
  6.  
  7.     This source code is based (with permission!) on the 6502 emulator by
  8.     Juergen Buchmueller.  It is released as part of the Mame emulator project.
  9.     Let me know if you intend to use this code in any other project.
  10.  
  11.  
  12.     NOTICE:
  13.  
  14.     This code is around 98% complete!  Several things are unimplemented,
  15.     some due to lack of time, some due to lack of documentation, mainly
  16.     due to lack of programs using these features.
  17.  
  18.     csh, csl opcodes are not supported.
  19.     set opcode and T flag behaviour are not supported.
  20.  
  21.     I am unsure if instructions like SBC take an extra cycle when used in
  22.     decimal mode.  I am unsure if flag B is set upon execution of rti.
  23.  
  24.     Cycle counts should be quite accurate, illegal instructions are assumed
  25.     to take two cycles.
  26.  
  27.  
  28.     Changelog, version 1.02:
  29.         JMP + indirect X (0x7c) opcode fixed.
  30.         SMB + RMB opcodes fixed in disassembler.
  31.         change_pc function calls removed.
  32.         TSB & TRB now set flags properly.
  33.         BIT opcode altered.
  34.  
  35.     Changelog, version 1.03:
  36.         Swapped IRQ mask for IRQ1 & IRQ2 (thanks Yasuhiro)
  37.  
  38.     Changelog, version 1.04, 28/9/99-22/10/99:
  39.         Adjusted RTI (thanks Karl)
  40.          TST opcodes fixed in disassembler (missing break statements in a case!).
  41.         TST behaviour fixed.
  42.         SMB/RMB/BBS/BBR fixed in disassembler.
  43.  
  44.     Changelog, version 1.05, 8/12/99-16/12/99:
  45.         Added CAB's timer implementation (note: irq ack & timer reload are changed).
  46.         Fixed STA IDX.
  47.         Fixed B flag setting on BRK.
  48.         Assumed CSH & CSL to take 2 cycles each.
  49.  
  50.         Todo:  Performance could be improved by precalculating timer fire position.
  51.  
  52.     Changelog, version 1.06, 4/5/00 - last opcode bug found?
  53.         JMP indirect was doing a EAL++; instead of EAD++; - Obviously causing
  54.         a corrupt read when L = 0xff!  This fixes Bloody Wolf and Trio The Punch!
  55.  
  56. ******************************************************************************/
  57.  
  58. #include "memory.h"
  59. #include "cpuintrf.h"
  60. #include "mamedbg.h"
  61. #include "h6280.h"
  62.  
  63. #include <stdio.h>
  64. #include <string.h>
  65.  
  66. extern FILE * errorlog;
  67. extern unsigned cpu_get_pc(void);
  68.  
  69. static UINT8 reg_layout[] = {
  70.     H6280_PC, H6280_S, H6280_P, H6280_A, H6280_X, H6280_Y, -1,
  71.     H6280_IRQ_MASK, H6280_TIMER_STATE, H6280_NMI_STATE, H6280_IRQ1_STATE, H6280_IRQ2_STATE, H6280_IRQT_STATE,
  72. #ifdef MAME_DEBUG
  73.     -1,
  74.     H6280_M1, H6280_M2, H6280_M3, H6280_M4, -1,
  75.     H6280_M5, H6280_M6, H6280_M7, H6280_M8,
  76. #endif
  77.     0
  78. };
  79.  
  80. /* Layout of the debugger windows x,y,w,h */
  81. static UINT8 win_layout[] = {
  82.     25, 0,55, 4,    /* register window (top rows) */
  83.      0, 0,24,22,    /* disassembler window (left colums) */
  84.     25, 5,55, 8,    /* memory #1 window (right, upper middle) */
  85.     25,14,55, 8,    /* memory #2 window (right, lower middle) */
  86.      0,23,80, 1,    /* command line window (bottom rows) */
  87. };
  88.  
  89. int     h6280_ICount = 0;
  90.  
  91. /****************************************************************************
  92.  * The 6280 registers.
  93.  ****************************************************************************/
  94. typedef struct
  95. {
  96.     PAIR  ppc;            /* previous program counter */
  97.     PAIR  pc;           /* program counter */
  98.     PAIR  sp;           /* stack pointer (always 100 - 1FF) */
  99.     PAIR  zp;           /* zero page address */
  100.     PAIR  ea;           /* effective address */
  101.     UINT8 a;            /* Accumulator */
  102.     UINT8 x;            /* X index register */
  103.     UINT8 y;            /* Y index register */
  104.     UINT8 p;            /* Processor status */
  105.     UINT8 mmr[8];       /* Hu6280 memory mapper registers */
  106.     UINT8 irq_mask;     /* interrupt enable/disable */
  107.     UINT8 timer_status; /* timer status */
  108.     UINT8 timer_ack;    /* timer acknowledge */
  109.     int timer_value;    /* timer interrupt */
  110.     int timer_load;        /* reload value */
  111.     int extra_cycles;    /* cycles used taking an interrupt */
  112.     int nmi_state;
  113.     int irq_state[3];
  114.     int (*irq_callback)(int irqline);
  115.  
  116. #if LAZY_FLAGS
  117.     int NZ;             /* last value (lazy N and Z flag) */
  118. #endif
  119.  
  120. }   h6280_Regs;
  121.  
  122. static  h6280_Regs  h6280;
  123.  
  124. #ifdef  MAME_DEBUG /* Need some public segmentation registers for debugger */
  125. UINT8    H6280_debug_mmr[8];
  126. #endif
  127.  
  128. /* include the macros */
  129. #include "h6280ops.h"
  130.  
  131. /* include the opcode macros, functions and function pointer tables */
  132. #include "tblh6280.c"
  133.  
  134. /*****************************************************************************/
  135.  
  136. void h6280_reset(void *param)
  137. {
  138.     int i;
  139.  
  140.     /* wipe out the h6280 structure */
  141.     memset(&h6280, 0, sizeof(h6280_Regs));
  142.  
  143.     /* set I and Z flags */
  144.     P = _fI | _fZ;
  145.  
  146.     /* stack starts at 0x01ff */
  147.     h6280.sp.d = 0x1ff;
  148.  
  149.     /* read the reset vector into PC */
  150.     PCL = RDMEM(H6280_RESET_VEC);
  151.     PCH = RDMEM((H6280_RESET_VEC+1));
  152.  
  153.     /* timer off by default */
  154.     h6280.timer_status=0;
  155.     h6280.timer_ack=1;
  156.  
  157.     /* clear pending interrupts */
  158.     for (i = 0; i < 3; i++)
  159.         h6280.irq_state[i] = CLEAR_LINE;
  160. }
  161.  
  162. void h6280_exit(void)
  163. {
  164.     /* nothing */
  165. }
  166.  
  167. int h6280_execute(int cycles)
  168. {
  169.     int in,lastcycle,deltacycle;
  170.     h6280_ICount = cycles;
  171.  
  172.     /* Subtract cycles used for taking an interrupt */
  173.     h6280_ICount -= h6280.extra_cycles;
  174.     h6280.extra_cycles = 0;
  175.     lastcycle = h6280_ICount;
  176.  
  177.     /* Execute instructions */
  178.     do
  179.     {
  180.         h6280.ppc = h6280.pc;
  181.  
  182. #ifdef  MAME_DEBUG
  183.          {
  184.             if (mame_debug)
  185.             {
  186.                 /* Copy the segmentation registers for debugger to use */
  187.                 int i;
  188.                 for (i=0; i<8; i++)
  189.                     H6280_debug_mmr[i]=h6280.mmr[i];
  190.  
  191.                 MAME_Debug();
  192.             }
  193.         }
  194. #endif
  195.  
  196.         /* Execute 1 instruction */
  197.         in=RDOP();
  198.         PCW++;
  199.         insnh6280[in]();
  200.  
  201.         /* Check internal timer */
  202.         if(h6280.timer_status)
  203.         {
  204.             deltacycle = lastcycle - h6280_ICount;
  205.             h6280.timer_value -= deltacycle;
  206.             if(h6280.timer_value<=0 && h6280.timer_ack==1)
  207.             {
  208.                 h6280.timer_ack=0;
  209.                 h6280_set_irq_line(2,ASSERT_LINE);
  210.             }
  211.         }
  212.         lastcycle = h6280_ICount;
  213.  
  214.         /* If PC has not changed we are stuck in a tight loop, may as well finish */
  215.         if( h6280.pc.d == h6280.ppc.d )
  216.         {
  217.             if (h6280_ICount > 0) h6280_ICount=0;
  218.         }
  219.  
  220.     } while (h6280_ICount > 0);
  221.  
  222.     /* Subtract cycles used for taking an interrupt */
  223.     h6280_ICount -= h6280.extra_cycles;
  224.     h6280.extra_cycles = 0;
  225.  
  226.     return cycles - h6280_ICount;
  227. }
  228.  
  229. unsigned h6280_get_context (void *dst)
  230. {
  231.     if( dst )
  232.         *(h6280_Regs*)dst = h6280;
  233.     return sizeof(h6280_Regs);
  234. }
  235.  
  236. void h6280_set_context (void *src)
  237. {
  238.     if( src )
  239.         h6280 = *(h6280_Regs*)src;
  240. }
  241.  
  242. unsigned h6280_get_pc (void)
  243. {
  244.     return PCD;
  245. }
  246.  
  247. void h6280_set_pc (unsigned val)
  248. {
  249.     PCW = val;
  250. }
  251.  
  252. unsigned h6280_get_sp (void)
  253. {
  254.     return S;
  255. }
  256.  
  257. void h6280_set_sp (unsigned val)
  258. {
  259.     S = val;
  260. }
  261.  
  262. unsigned h6280_get_reg (int regnum)
  263. {
  264.     switch( regnum )
  265.     {
  266.         case H6280_PC: return PCD;
  267.         case H6280_S: return S;
  268.         case H6280_P: return P;
  269.         case H6280_A: return A;
  270.         case H6280_X: return X;
  271.         case H6280_Y: return Y;
  272.         case H6280_IRQ_MASK: return h6280.irq_mask;
  273.         case H6280_TIMER_STATE: return h6280.timer_status;
  274.         case H6280_NMI_STATE: return h6280.nmi_state;
  275.         case H6280_IRQ1_STATE: return h6280.irq_state[0];
  276.         case H6280_IRQ2_STATE: return h6280.irq_state[1];
  277.         case H6280_IRQT_STATE: return h6280.irq_state[2];
  278. #ifdef MAME_DEBUG
  279.         case H6280_M1: return h6280.mmr[0];
  280.         case H6280_M2: return h6280.mmr[1];
  281.         case H6280_M3: return h6280.mmr[2];
  282.         case H6280_M4: return h6280.mmr[3];
  283.         case H6280_M5: return h6280.mmr[4];
  284.         case H6280_M6: return h6280.mmr[5];
  285.         case H6280_M7: return h6280.mmr[6];
  286.         case H6280_M8: return h6280.mmr[7];
  287. #endif
  288.         case REG_PREVIOUSPC: return h6280.ppc.d;
  289.         default:
  290.             if( regnum <= REG_SP_CONTENTS )
  291.             {
  292.                 unsigned offset = S + 2 * (REG_SP_CONTENTS - regnum);
  293.                 if( offset < 0x1ff )
  294.                     return RDMEM( offset ) | ( RDMEM( offset+1 ) << 8 );
  295.             }
  296.     }
  297.     return 0;
  298. }
  299.  
  300. void h6280_set_reg (int regnum, unsigned val)
  301. {
  302.     switch( regnum )
  303.     {
  304.         case H6280_PC: PCW = val; break;
  305.         case H6280_S: S = val; break;
  306.         case H6280_P: P = val; break;
  307.         case H6280_A: A = val; break;
  308.         case H6280_X: X = val; break;
  309.         case H6280_Y: Y = val; break;
  310.         case H6280_IRQ_MASK: h6280.irq_mask = val; CHECK_IRQ_LINES; break;
  311.         case H6280_TIMER_STATE: h6280.timer_status = val; break;
  312.         case H6280_NMI_STATE: h6280_set_nmi_line( val ); break;
  313.         case H6280_IRQ1_STATE: h6280_set_irq_line( 0, val ); break;
  314.         case H6280_IRQ2_STATE: h6280_set_irq_line( 1, val ); break;
  315.         case H6280_IRQT_STATE: h6280_set_irq_line( 2, val ); break;
  316. #ifdef MAME_DEBUG
  317.         case H6280_M1: h6280.mmr[0] = val; break;
  318.         case H6280_M2: h6280.mmr[1] = val; break;
  319.         case H6280_M3: h6280.mmr[2] = val; break;
  320.         case H6280_M4: h6280.mmr[3] = val; break;
  321.         case H6280_M5: h6280.mmr[4] = val; break;
  322.         case H6280_M6: h6280.mmr[5] = val; break;
  323.         case H6280_M7: h6280.mmr[6] = val; break;
  324.         case H6280_M8: h6280.mmr[7] = val; break;
  325. #endif
  326.         default:
  327.             if( regnum <= REG_SP_CONTENTS )
  328.             {
  329.                 unsigned offset = S + 2 * (REG_SP_CONTENTS - regnum);
  330.                 if( offset < 0x1ff )
  331.                 {
  332.                     WRMEM( offset, val & 0xff );
  333.                     WRMEM( offset+1, (val >> 8) & 0xff );
  334.                 }
  335.             }
  336.     }
  337. }
  338.  
  339. /*****************************************************************************/
  340.  
  341. void h6280_set_nmi_line(int state)
  342. {
  343.     if (h6280.nmi_state == state) return;
  344.     h6280.nmi_state = state;
  345.     if (state != CLEAR_LINE)
  346.     {
  347.         DO_INTERRUPT(H6280_NMI_VEC);
  348.     }
  349. }
  350.  
  351. void h6280_set_irq_line(int irqline, int state)
  352. {
  353.     h6280.irq_state[irqline] = state;
  354.  
  355.     /* If line is cleared, just exit */
  356.     if (state == CLEAR_LINE) return;
  357.  
  358.     /* Check if interrupts are enabled and the IRQ mask is clear */
  359.     CHECK_IRQ_LINES;
  360. }
  361.  
  362. void h6280_set_irq_callback(int (*callback)(int irqline))
  363. {
  364.     h6280.irq_callback = callback;
  365. }
  366.  
  367. /****************************************************************************
  368.  * Return a formatted string for a register
  369.  ****************************************************************************/
  370. const char *h6280_info(void *context, int regnum)
  371. {
  372.     static char buffer[32][47+1];
  373.     static int which = 0;
  374.     h6280_Regs *r = context;
  375.  
  376.     which = ++which % 32;
  377.     buffer[which][0] = '\0';
  378.     if( !context )
  379.         r = &h6280;
  380.  
  381.     switch( regnum )
  382.     {
  383.         case CPU_INFO_REG+H6280_PC: sprintf(buffer[which], "PC:%04X", r->pc.w.l); break;
  384.         case CPU_INFO_REG+H6280_S: sprintf(buffer[which], "S:%02X", r->sp.b.l); break;
  385.         case CPU_INFO_REG+H6280_P: sprintf(buffer[which], "P:%02X", r->p); break;
  386.         case CPU_INFO_REG+H6280_A: sprintf(buffer[which], "A:%02X", r->a); break;
  387.         case CPU_INFO_REG+H6280_X: sprintf(buffer[which], "X:%02X", r->x); break;
  388.         case CPU_INFO_REG+H6280_Y: sprintf(buffer[which], "Y:%02X", r->y); break;
  389.         case CPU_INFO_REG+H6280_IRQ_MASK: sprintf(buffer[which], "IM:%02X", r->irq_mask); break;
  390.         case CPU_INFO_REG+H6280_TIMER_STATE: sprintf(buffer[which], "TMR:%02X", r->timer_status); break;
  391.         case CPU_INFO_REG+H6280_NMI_STATE: sprintf(buffer[which], "NMI:%X", r->nmi_state); break;
  392.         case CPU_INFO_REG+H6280_IRQ1_STATE: sprintf(buffer[which], "IRQ1:%X", r->irq_state[0]); break;
  393.         case CPU_INFO_REG+H6280_IRQ2_STATE: sprintf(buffer[which], "IRQ2:%X", r->irq_state[1]); break;
  394.         case CPU_INFO_REG+H6280_IRQT_STATE: sprintf(buffer[which], "IRQT:%X", r->irq_state[2]); break;
  395. #ifdef MAME_DEBUG
  396.         case CPU_INFO_REG+H6280_M1: sprintf(buffer[which], "M1:%02X", r->mmr[0]); break;
  397.         case CPU_INFO_REG+H6280_M2: sprintf(buffer[which], "M2:%02X", r->mmr[1]); break;
  398.         case CPU_INFO_REG+H6280_M3: sprintf(buffer[which], "M3:%02X", r->mmr[2]); break;
  399.         case CPU_INFO_REG+H6280_M4: sprintf(buffer[which], "M4:%02X", r->mmr[3]); break;
  400.         case CPU_INFO_REG+H6280_M5: sprintf(buffer[which], "M5:%02X", r->mmr[4]); break;
  401.         case CPU_INFO_REG+H6280_M6: sprintf(buffer[which], "M6:%02X", r->mmr[5]); break;
  402.         case CPU_INFO_REG+H6280_M7: sprintf(buffer[which], "M7:%02X", r->mmr[6]); break;
  403.         case CPU_INFO_REG+H6280_M8: sprintf(buffer[which], "M8:%02X", r->mmr[7]); break;
  404. #endif
  405.         case CPU_INFO_FLAGS:
  406.             sprintf(buffer[which], "%c%c%c%c%c%c%c%c",
  407.                 r->p & 0x80 ? 'N':'.',
  408.                 r->p & 0x40 ? 'V':'.',
  409.                 r->p & 0x20 ? 'R':'.',
  410.                 r->p & 0x10 ? 'B':'.',
  411.                 r->p & 0x08 ? 'D':'.',
  412.                 r->p & 0x04 ? 'I':'.',
  413.                 r->p & 0x02 ? 'Z':'.',
  414.                 r->p & 0x01 ? 'C':'.');
  415.             break;
  416.         case CPU_INFO_NAME: return "HuC6280";
  417.         case CPU_INFO_FAMILY: return "Hudsonsoft 6280";
  418.         case CPU_INFO_VERSION: return "1.06";
  419.         case CPU_INFO_FILE: return __FILE__;
  420.         case CPU_INFO_CREDITS: return "Copyright (c) 1999, 2000 Bryan McPhail, mish@tendril.co.uk";
  421.         case CPU_INFO_REG_LAYOUT: return (const char*)reg_layout;
  422.         case CPU_INFO_WIN_LAYOUT: return (const char*)win_layout;
  423.     }
  424.     return buffer[which];
  425. }
  426.  
  427. unsigned h6280_dasm(char *buffer, unsigned pc)
  428. {
  429. #ifdef MAME_DEBUG
  430.     return Dasm6280(buffer,pc);
  431. #else
  432.     sprintf( buffer, "$%02X", cpu_readop(pc) );
  433.     return 1;
  434. #endif
  435. }
  436.  
  437. /*****************************************************************************/
  438.  
  439. READ_HANDLER( H6280_irq_status_r )
  440. {
  441.     int status;
  442.  
  443.     switch (offset)
  444.     {
  445.         case 0: /* Read irq mask */
  446.             return h6280.irq_mask;
  447.  
  448.         case 1: /* Read irq status */
  449.             status=0;
  450.             if(h6280.irq_state[1]!=CLEAR_LINE) status|=1; /* IRQ 2 */
  451.             if(h6280.irq_state[0]!=CLEAR_LINE) status|=2; /* IRQ 1 */
  452.             if(h6280.irq_state[2]!=CLEAR_LINE) status|=4; /* TIMER */
  453.             return status;
  454.     }
  455.  
  456.     return 0;
  457. }
  458.  
  459. WRITE_HANDLER( H6280_irq_status_w )
  460. {
  461.     switch (offset)
  462.     {
  463.         case 0: /* Write irq mask */
  464.             h6280.irq_mask=data&0x7;
  465.             CHECK_IRQ_LINES;
  466.             break;
  467.  
  468.         case 1: /* Timer irq ack - timer is reloaded here */
  469.             h6280.timer_value = h6280.timer_load;
  470.             h6280.timer_ack=1; /* Timer can't refire until ack'd */
  471.             break;
  472.     }
  473. }
  474.  
  475. READ_HANDLER( H6280_timer_r )
  476. {
  477.     switch (offset) {
  478.         case 0: /* Counter value */
  479.             return (h6280.timer_value/1024)&127;
  480.  
  481.         case 1: /* Read counter status */
  482.             return h6280.timer_status;
  483.     }
  484.  
  485.     return 0;
  486. }
  487.  
  488. WRITE_HANDLER( H6280_timer_w )
  489. {
  490.     switch (offset) {
  491.         case 0: /* Counter preload */
  492.             h6280.timer_load=h6280.timer_value=((data&127)+1)*1024;
  493.             return;
  494.  
  495.         case 1: /* Counter enable */
  496.             if(data&1)
  497.             {    /* stop -> start causes reload */
  498.                 if(h6280.timer_status==0) h6280.timer_value=h6280.timer_load;
  499.             }
  500.             h6280.timer_status=data&1;
  501.             return;
  502.     }
  503. }
  504.  
  505. /*****************************************************************************/
  506.